﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
using System.Net;
using System.Net.Mail;
using CHGK.web.UI;
using CHGK.web.UI.Models;
using CHGK.web.UI.Core;
using ChGK.Data;

namespace CHGK.web.UI.Controllers
{
    public class SuperuserController : Controller, IDisposable
    {
        //
        // GET: /Superuser/
        private DataManager _DataManager;
        
        public SuperuserController()
        {
            _DataManager = new DataManager();
        }

        public Tour GetValidTourAndQuestionNumbers(int CompetitionID, ref int QuestionNumber, int TourNumber)
        {
            Tour _Tour = new Tour();

            if (QuestionNumber == 0)
            {
                ModelState.AddModelError("QuestionNumber", "Пожалуйста, укажите номер вопроса");
                return _Tour;
            }

            if (TourNumber == 0)
            {
                int i = 1;
                _Tour = _DataManager.Tours.GetTour(CompetitionID, i);
                while (QuestionNumber > _Tour.NumberOfQuestions)
                {
                    i++;
                    QuestionNumber -= _Tour.NumberOfQuestions;
                    _Tour = _DataManager.Tours.GetTour(CompetitionID, i);
                    if (_Tour == null)
                    {
                        ModelState.AddModelError("QuestionNumber", "Вопроса с таким номером не существует");
                        break;
                    }
                }
            }
            else
            {
                _Tour = _DataManager.Tours.GetTour(CompetitionID, TourNumber);
                if (_Tour == null)
                {
                    ModelState.AddModelError("TourNumber", "Такого тура не существует");
                }
                else if (QuestionNumber > _Tour.NumberOfQuestions)
                {
                    ModelState.AddModelError("QuestionNumber", "Вопроса с таким номером не существует. Для использования сквозной нумерации поставьте в поле 'номер тура' ноль");
                }
            }

            return _Tour;
        }

        private short[] GetFreeNumbers(int CompetitionID, int NumberOfFreeNumbers)
        {
            short[] _FreeNumbers = new short[NumberOfFreeNumbers];
            IEnumerable<Team> _Teams = _DataManager.Teams.GetTeams(CompetitionID);
            short LastPosition = 0, i = 0;

            foreach (Team t in _Teams)
            {
                if (t.Number - LastPosition > 1)
                {
                    for (int j = LastPosition + 1; j < t.Number; j++)
                    {
                        if (i > NumberOfFreeNumbers) return _FreeNumbers;
                        _FreeNumbers[i] = (short)j;
                        i++;
                    }
                }
                LastPosition = t.Number;
            }

            while (i < NumberOfFreeNumbers)
            {
                _FreeNumbers[i] = (short)(LastPosition + 1);
                LastPosition++;
                i++;
            }

            return _FreeNumbers;
        }

        private void PrepareToReturnToSuperuserPage(User CurrentUser)
        {
            ViewData.Model = CurrentUser;
            ViewData["Teams"] = _DataManager.Teams.GetTeams(CurrentUser.CompetitionID);
        }

        private void CheckSuperuserPassword(User CurrentUser, string SuperuserPassword, string ModelErrorName)
        {
            
            if (SuperuserPassword == "")
            {
                ModelState.AddModelError(ModelErrorName, "Пожалуйста, введите ваш пароль");
            }
            else if (SuperuserPassword != CurrentUser.HashCode)
            {
                ModelState.AddModelError(ModelErrorName, "Введённый вами пароль неверен");
            }
        }

        private void ValidateDataIsNull(string Data, string ErrorName, string ErrorMessage)
        {
            if (Data == "")
            {
                ModelState.AddModelError(ErrorName, "Пожалуйста, введите " + ErrorMessage);
            }
        }

        [Authorize(Roles = "Superuser")]
        public ActionResult SuperuserPage(int? TeamID)
        {
            User _User = _DataManager.Users.GetUser(User.Identity.Name);

            if (TeamID.HasValue)
            {
                ViewData["TeamID"] = TeamID.Value;
            }
            PrepareToReturnToSuperuserPage(_User);
            return View();

        }

        [HttpGet]
        [Authorize(Roles = "Superuser")]
        public ActionResult CheckAnswer()
        {
            CheckAnswerModel Model = new CheckAnswerModel();
            Competition _Competition = _DataManager.Competitions.GetCompetitionByUserLogin(User.Identity.Name);
            Model.CompetitionID = _Competition.ID;
            ViewData.Model = Model;

            return View();
        }

        [HttpPost]
        [Authorize(Roles = "Superuser")]
        public ActionResult CheckAnswer(CheckAnswerModel Model)
        {
            if (Model.TeamNumber == 0 || Model.TeamNumber == null)
            {
                ModelState.AddModelError("TeamNumber", "Пожалуйста, укажите номер команды");
                ViewData.Model = Model;
                return View();
            }

            Team _Team = _DataManager.Teams.GetTeam(Model.CompetitionID, Model.TeamNumber.Value);
            
            if (_Team == null)
            {
                ModelState.AddModelError("TeamNumber", "Команды с таким номером не существует");
                ViewData.Model = Model;
                return View();
            }

            int _QuestionNumber = Model.QuestionNumber ?? 0;
            int _TourNumber = Model.TourNumber ?? 0;
            Tour _Tour = this.GetValidTourAndQuestionNumbers(Model.CompetitionID, ref _QuestionNumber, _TourNumber);

            if (!ModelState.IsValid)
            {
                ViewData.Model = Model;
                return View();
            }

            Answer _Answer = _DataManager.Answers.GetAnswer(_Team.ID, _Tour.ID, _QuestionNumber);
                
            if (_Answer == null)
            {
                ModelState.AddModelError("Answer", "От данной команды ответ на этот вопрос получен не был");
            }
            else
            {
                if (Model.Answer != null)
                {
                    _Answer.IsCorrect = Model.IsCorrect;
                    _DataManager.Answers.UpdateAnswer(_Answer);
                    return RedirectToAction("CheckAnswer");
                }
               
                Model.TourNumber = _Tour.NumberInCompetition;
                Model.QuestionNumber = _QuestionNumber;
                Model.Answer = _Answer.Value;
                Model.IsCorrect = _Answer.IsCorrect;

            }

            ViewData.Model = Model;
            return View();
        }

        [HttpGet]
        [Authorize(Roles = "Superuser")]
        public ActionResult CheckingAnswers(int QuestionNumber, int TourNumber)
        {
            Competition _Competition = _DataManager.Competitions.GetCompetitionByUserLogin(User.Identity.Name);
            Tour _Tour = _DataManager.Tours.GetTour(_Competition.ID, TourNumber);

            if (_Tour != null && QuestionNumber < _Tour.NumberOfQuestions)
            {
                ViewData["CompetitionID"] = _Competition.ID;
                ViewData["TourNumber"] = TourNumber;
                ViewData["QuestionNumber"] = QuestionNumber + 1;
            }
            else
            {
                ViewData["CompetitionID"] = _Competition.ID;
                ViewData["TourNumber"] = null;
                ViewData["QuestionNumber"] = null;
            }
            return View();
        }

        [HttpPost]
        public ActionResult CheckingAnswers(int CompetitionID, int? QuestNumber, int? TNumber)
        {
            int _QuestionNumber = QuestNumber ?? 0;
            int _TourNumber = TNumber ?? 0;
            Tour _Tour = this.GetValidTourAndQuestionNumbers(CompetitionID, ref _QuestionNumber, _TourNumber);

            if (!ModelState.IsValid)
            {
                return View();
            }


            IEnumerable<Answer> _Answers = _DataManager.Answers.GetAnswers(_Tour.ID, _QuestionNumber);
           
           if (_Answers.Count() == 0)
            {
                ModelState.AddModelError("Answers", "На данный вопрос ни одного ответа пока не поступило");
                ViewData["TourNumber"] = 0;
                return View();
            }

            return RedirectToAction("SubmitAnswers", new { QuestionNumber = _QuestionNumber, TourID = _Tour.ID});
        }

        [HttpGet]
        [Authorize(Roles = "Superuser")]
        public ActionResult SubmitAnswers(int QuestionNumber, int TourID)
        {
            Tour _Tour = _DataManager.Tours.GetTour(TourID);

            ViewData["QuestionNumber"] = QuestionNumber;
            ViewData["TourNumber"] = _Tour.NumberInCompetition;
            ViewData["Answers"] = (IEnumerable<Answer>)_DataManager.Answers.GetAnswers(TourID, QuestionNumber);

            return View();
        }

        [HttpPost]
        [Authorize(Roles = "Superuser")]
        public ActionResult SubmitAnswers(int QuestionNumber, int TourNumber, IEnumerable<int> AnswerID, int[] IsCorrect)
        {
            for (int i = 0; i < AnswerID.Count(); i++)
            {
                if (IsCorrect[i] == 2)
                {
                    _DataManager.Answers.UpdateAnswer(AnswerID.ElementAt(i), true);
                }
                else if (IsCorrect[i] == 1)
                {
                    _DataManager.Answers.UpdateAnswer(AnswerID.ElementAt(i), false);
                }
            }

            return RedirectToAction("CheckingAnswers", new { QuestionNumber = QuestionNumber, TourNumber = TourNumber});
        }

        [HttpPost]
        [Authorize(Roles = "Superuser")]
        public ActionResult PreAddTeams(int? NumberOfNewTeams)
        {
            if (NumberOfNewTeams == null)
            {
                ModelState.AddModelError("NumberOfNewTeams", "Пожалуйста, введите количество создаваемых команд");
            }
            else if (NumberOfNewTeams <= 0)
            {
                ModelState.AddModelError("NumberOfNewTeams", "Количество создаваемых команд должно быть больше нуля!");
            }

            if (!ModelState.IsValid)
            {
                User _User = _DataManager.Users.GetUser(User.Identity.Name);

                PrepareToReturnToSuperuserPage(_User);
                return View("SuperuserPage");
            }

            return RedirectToAction("AddTeams", new { NumberOfNewTeams = NumberOfNewTeams.Value });
        }

        [HttpGet]
        [Authorize(Roles = "Superuser")]
        public ActionResult AddTeams(int NumberOfNewTeams)
        {
            int CompetitionID = _DataManager.Competitions.GetCompetitionByUserLogin(User.Identity.Name).ID;
            short[] FreeNumbers = GetFreeNumbers(CompetitionID, NumberOfNewTeams);

            ViewData.Model = FreeNumbers;
            return View();
        }

        [HttpPost]
        [Authorize(Roles = "Superuser")]
        public ActionResult AddTeams(short?[] TeamNumber, string[] TeamName, string[] TeamCity)
        {
            int i, j;
            for (i = 0; i < TeamNumber.Count(); i++)
            {
                for (j = i + 1; j < TeamNumber.Count(); j++)
                {
                    if (TeamNumber[i] == TeamNumber[j])
                    {
                        ModelState.AddModelError("TeamNumber[" + i.ToString() + "]", "Такой же номер введён для другой команды.");
                        ModelState.AddModelError("TeamNumber[" + j.ToString() + "]", "Такой же номер введён для другой команды.");
                    }
                }
                if (TeamNumber[i] == null)
                {
                    ModelState.AddModelError("TeamNumber[" + i.ToString() + "]", "Пожалуйста, введите номер команды");
                }
                if (TeamName[i] == "")
                {
                    ModelState.AddModelError("TeamName[" + i.ToString() + "]", "Пожалуйста, введите название команды");
                }
                if (TeamCity[i] == "")
                {
                    ModelState.AddModelError("TeamCity[" + i.ToString() + "]", "Пожалуйста, введите город базирования команды");
                }
            }

            if (!ModelState.IsValid)
            {
                ViewData.Model = TeamNumber;
                return View();
            }

            int CompetitionID = _DataManager.Competitions.GetCompetitionByUserLogin(User.Identity.Name).ID;
            IEnumerable<Team> _Teams = _DataManager.Teams.GetTeams(CompetitionID);
            
            foreach (Team t in _Teams)
            {
                for (i = 0; i < TeamNumber.Count(); i++)
                {
                    if (TeamNumber[i] == t.Number)
                    {
                            ModelState.AddModelError("TeamNumber[" + i.ToString() + "]", "Команда с таким номером уже существует. Пожалуйста, выберите другой.");
                    }
                }
            }

            if (!ModelState.IsValid)
            {
                ViewData.Model = TeamNumber;
                return View();
            }

            string ShortDescription = User.Identity.Name.Substring(0, User.Identity.Name.IndexOf('-'));
            string UserLogin;
            string CompetitionType = _DataManager.Competitions.GetCompetition(CompetitionID).Type;
            int TeamID;
            Random rnd = new Random();
            Password PasswordInstance = new Password();


            for (i = 0; i < TeamNumber.Count(); i++)
            {
                if (CompetitionType == "Синхрон")
                {
                    if (TeamNumber[i] < 10)
                    {
                        UserLogin = _DataManager.Users.CreateUser(ShortDescription + "-00" + TeamNumber[i].ToString(), PasswordInstance.CreatePassword(rnd.Next(5, 7)), "User", CompetitionID);
                    }
                    else if (TeamNumber[i] >= 10 && TeamNumber[i] < 100)
                    {
                        UserLogin = _DataManager.Users.CreateUser(ShortDescription + "-0" + TeamNumber[i].ToString(), PasswordInstance.CreatePassword(rnd.Next(5, 7)), "User", CompetitionID);
                    }
                    else
                    {
                        UserLogin = _DataManager.Users.CreateUser(ShortDescription + "-" + TeamNumber[i].ToString(), PasswordInstance.CreatePassword(rnd.Next(5, 7)), "User", CompetitionID);
                    }
                }
                else
                {
                    if (TeamNumber[i] < 10)
                    {
                        UserLogin = _DataManager.Users.CreateUser(ShortDescription + "-0" + TeamNumber[i].ToString(), PasswordInstance.CreatePassword(rnd.Next(5, 7)), "User", CompetitionID);
                    }
                    else
                    {
                        UserLogin = _DataManager.Users.CreateUser(ShortDescription + "-" + TeamNumber[i].ToString(), PasswordInstance.CreatePassword(rnd.Next(5, 7)), "User", CompetitionID);
                    }
                }
                TeamID = _DataManager.Teams.CreateTeam(UserLogin, CompetitionID, TeamNumber[i].Value, TeamName[i], TeamCity[i]);
                _DataManager.Users.AddTeam(UserLogin, TeamID); 
            }
            return RedirectToAction("SuperuserPage");
        }

        [HttpPost]
        [Authorize(Roles = "Superuser")]
        public ActionResult ShowLoginsAndPasswords(string SuperuserPassword)
        {
            User _User = _DataManager.Users.GetUser(User.Identity.Name);

            CheckSuperuserPassword(_User, SuperuserPassword, "SuperuserPassword");
            
            if (!ModelState.IsValid)
            {
                PrepareToReturnToSuperuserPage(_User);
                return View("SuperuserPage");
            }

            IEnumerable<User> _Users = _DataManager.Users.GetUsers(_User.CompetitionID, "User");
            string[] _TeamCaptions = new string[_Users.Count()];

            for (int i = 0; i < _Users.Count(); i++)
            {
                _TeamCaptions[i] = _DataManager.Teams.GetTeam((int)_Users.ElementAt(i).TeamID).Caption;
            }

            ViewData.Model = _TeamCaptions;
            ViewData["Users"] = _Users;
            return View();
        }

        public ActionResult EditTeam(int TeamID, int? TeamNumberNew, int TeamNumberOld, string TeamName, string TeamCity)
        {
            if (TeamName == "")
            {
                ModelState.AddModelError("EditTeam", "Пожалуйста, введите название команды");
            }
            else if (TeamCity == "")
            {
                ModelState.AddModelError("EditTeam", "Пожалуйста, введите город базирования");
            }
            else if (TeamNumberNew == null)
            {
                ModelState.AddModelError("EditTeam", "Пожалуйста, введите номер команды");
            }
            else if (TeamNumberNew.Value <= 0)
            {
                ModelState.AddModelError("EditTeam", "Номер команды - величина положительная");
            }
            else if (TeamNumberNew.Value != TeamNumberOld)
            {
                int _CompetitionID = _DataManager.Competitions.GetCompetitionByUserLogin(User.Identity.Name).ID;
                foreach (Team t in _DataManager.Teams.GetTeams(_CompetitionID))
                {
                    if (t.Number == TeamNumberNew.Value)
                    {
                        ModelState.AddModelError("EditTeam", "Этот номер уже используется. Пожалуйста, введите другой");
                        break;
                    }
                }
            }

            if (!ModelState.IsValid)
            {
                ViewData["TeamID"] = TeamID;
                User _User = _DataManager.Users.GetUser(User.Identity.Name);
                PrepareToReturnToSuperuserPage(_User);
                return View("SuperuserPage");
            }

            _DataManager.Teams.UpdateTeam(TeamID, TeamName, TeamCity, TeamNumberNew.Value);
            return RedirectToAction("SuperuserPage");
        }

        public ActionResult DeleteTeam(int TeamID)
        {
            _DataManager.Teams.DeleteTeam(TeamID);
            _DataManager.Users.DeleteUser(TeamID);

            return RedirectToAction("SuperuserPage");

        }

        public ActionResult AddSuperuser(string SuperuserPassword)
        {
            User _User = _DataManager.Users.GetUser(User.Identity.Name);

            CheckSuperuserPassword(_User, SuperuserPassword, "SuperuserPassword2");
            
            if (!ModelState.IsValid)
            {
                PrepareToReturnToSuperuserPage(_User);
                return View("SuperuserPage");
            }

            Random rnd = new Random();
            Password PasswordInstance = new Password();
            int LastSuperuserNumber = _DataManager.Users.GetUsers(_User.CompetitionID, "Superuser").Count();

            string NewUserLogin = _DataManager.Users.CreateUser(User.Identity.Name.Substring(0, User.Identity.Name.IndexOf('s') + 1) + (LastSuperuserNumber + 1).ToString(), PasswordInstance.CreatePassword(rnd.Next(8, 11)), "Superuser", _User.CompetitionID);
            
            _User = _DataManager.Users.GetUser(NewUserLogin);

            ViewData.Model = _User;
            return View();
        }

        public ActionResult FinalizeCompetition(bool IsEnded)
        {
            Competition _Competition = _DataManager.Competitions.GetCompetitionByUserLogin(User.Identity.Name);
            
            if (IsEnded == _Competition.IsEnded)
            {
                ModelState.AddModelError("FinalizeCompetition", "Изменения не обнаружены");
                User _User = _DataManager.Users.GetUser(User.Identity.Name);
                PrepareToReturnToSuperuserPage(_User);
                return View("SuperuserPage");
            }
            
            _DataManager.Competitions.UpdateCompetition(_Competition.ID, IsEnded);

            string MailSubject, MailBody;

            if (IsEnded == true)
            {
                MailSubject = "Завершение турнира ";
                MailBody = "Организаторы отметили данный турнир как завершившийся.";
            }
            else
            {
                MailSubject = "Отмена завершения турнира ";
                MailBody = "Организаторы сняли отметку о заершении.";
            }

            MailMessage message = new MailMessage(); // создание нового письма
            message.To.Add("somebody331@gmail.com"); // добавление адреса получателя
            message.From = new MailAddress("system@chgkwebsuite.ru", "chgkwebsuite.ru"); // указание имени и адреса отправителя
            message.Subject = MailSubject + _DataManager.Competitions.GetName(_Competition.ID); // указание темы письма 
            message.BodyEncoding = System.Text.Encoding.UTF8; // указание кодировки письма
            message.IsBodyHtml = false; // указание формата письма (true - HTML, false - не HTML)
            message.Body = MailBody; // указание текста (тела) письма

            SmtpClient client = new SmtpClient("smtp.chgkwebsuite.ru", 25); // создание нового подключения к серверу "smtp.domain.tld"
            client.DeliveryMethod = SmtpDeliveryMethod.Network; // определяет метод отправки сообщений
            client.EnableSsl = false; // отключает необходимость использования защищенного соединения с сервером
            client.UseDefaultCredentials = false; // отключение использования реквизитов авторизации "по-умолчанию"
            client.Credentials = new NetworkCredential("postmaster@chgkwebsuite.ru", "po4parka2tin"); // указание нужных реквизитов (имени пользователя и пароля) для авторизации на SMTP-сервере
            client.Send(message); // отправка сообщения

            ViewData["IsEnded"] = IsEnded;
            return View();

            

        }

        [HttpGet]
        public ActionResult PasswordChange()
        {
            return View();
        }

        [HttpPost]
        [Authorize(Roles = "Superuser")]
        public ActionResult PasswordChange(string OldPassword, string NewPassword, string NewPasswordConfirm)
        {
            User _User = _DataManager.Users.GetUser(User.Identity.Name);

            ValidateDataIsNull(OldPassword, "OldPassword", "старый пароль");
            ValidateDataIsNull(NewPassword, "NewPassword", "новый пароль");
            ValidateDataIsNull(NewPasswordConfirm, "NewPasswordConfirm", "подтверждение нового пароля");

            if (!ModelState.IsValid)
            {
                return View();
            }

            if (OldPassword != _User.HashCode)
            {
                ModelState.AddModelError("OldPassword", "Введённый пароль неверен");
            }
            else if (NewPassword != NewPasswordConfirm)
            {
                ModelState.AddModelError("NewPasswordConfirm", "Новый пароль не совпал с подтверждением");
            }

            if (ModelState.IsValid)
            {
                _DataManager.Users.UpdateUser(_User.Login, NewPassword);
                ViewData["Success"] = true;
                return View();
            }

            return View();
        }

        public ActionResult DeleteUserCache(string UserLogin)
        {
            if (UserLogin == "")
            {
                ModelState.AddModelError("DeleteUserCache", "Введите логин пользователя");
            }

            if (!ModelState.IsValid)
            {
                User _User = _DataManager.Users.GetUser(User.Identity.Name);
                PrepareToReturnToSuperuserPage(_User);
                return View("SuperuserPage");
            }

            System.Web.HttpContext.Current.Cache.Remove(UserLogin);
            return RedirectToAction("DeleteUserCacheSuccess");
        }

        public ActionResult DeleteUserCacheSuccess()
        {
            return View();
        }

        [HttpPost]
        public ActionResult TimeStop(string returnUrl)
        {
            Competition _Competition = _DataManager.Competitions.GetCompetitionByUserLogin(User.Identity.Name);
            IEnumerable<Team> _Teams = _DataManager.Teams.GetTeams(_Competition.ID);
            Tour _Tour = _DataManager.Tours.GetTour(_Competition.ID, 1);
            int? QuestionNumber = GetCurrentTourAndQuestionNumbers(_Competition, _Teams, ref _Tour);

            if (QuestionNumber != null)
            {
                IList<Answer> _Answers = _DataManager.Answers.GetAnswers(_Tour.ID, QuestionNumber.Value).ToList();
                foreach (Answer a in _Answers)
                {
                    _DataManager.Answers.UpdateAnswer(false, a.ID);
                }
                Session["CheckedQuestion"] = "Последний проверенный вопрос: №" + QuestionNumber.ToString() + ", тур №" + _Tour.NumberInCompetition.ToString();
            }

            

            return Redirect(Request.UrlReferrer.ToString());
        }

        private int? GetCurrentTourAndQuestionNumbers(Competition Competition, IEnumerable<Team> Teams, ref Tour Tour)
        {
            Team _Team;
            Answer _Answer;
            Random rnd = new Random();
            int QuestionNumber = 1, k;

            while (true)
            {
                while (QuestionNumber <= Tour.NumberOfQuestions)
                {
                    k = 0;
                    for (int i = 1; i <= 3; i++)
                    {
                        _Team = Teams.ElementAt(rnd.Next(Teams.Count() - 1));
                        _Answer = _DataManager.Answers.GetAnswer(_Team.ID, Tour.ID, QuestionNumber);

                        if (_Answer == null)
                        {
                            k++;
                        }
                        else
                        {
                            if (_Answer.isLate == null)
                            {
                                return QuestionNumber;
                            }

                            break;
                        }
                    }

                    if (k == 3) return null;
                    QuestionNumber++;
                }

                Tour = _DataManager.Tours.GetTour(Competition.ID, Tour.NumberInCompetition + 1);
                QuestionNumber = 1;
                if (Tour == null) return null;
            }
        }
    }
}
